package com.onpositive.mediawiki.propertyparser;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.w3c.dom.Element;

import com.onpositive.utils.StringPool;
import com.onpositive.wikistorage.LinkStorage;
import com.onpositive.wikistorage.PropertyAnalyzer;
import com.onpositive.wikistorage.PropertyStats;

public class ParsedCategory {// implements IStringPoolProvider{

	private HashMap<String, ParsedDocument> documents = new HashMap<String, ParsedDocument>();
	private HashMap<String, ParsedDocument> ldocuments = new HashMap<String, ParsedDocument>();
	private HashSet<String> propertyNames = new HashSet<String>();
	private PropertyAnalyzer analyzer;
	private Map<String, PropertyCharacteristic> characteristicsMap = createCharacteristicsMap();

	private LinkStorage refs = new LinkStorage("Refs");
	private LinkStorage captions = new LinkStorage("Captions");

	private HashMap<String, PropertyGroup> propertyGroups = new HashMap<String, PropertyGroup>();
	private String rootPath;

	private StringPool wikiRefsPool = new StringPool();

	public ParsedCategory(String rootPath) {
		this.rootPath = rootPath;
	}

	protected Map<String, PropertyCharacteristic> createCharacteristicsMap() {
		return new HashMap<String, PropertyCharacteristic>();
	}

	public HashMap<String, PropertyGroup> getPropertyGroups() {
		return propertyGroups;
	}

	public void addPropertyGroup(String name, String parent) {
		propertyGroups.put(name, new PropertyGroup(name, parent, this));
	}

	public void addPropertyGroup(PropertyGroup group) {
		group.setCategory(this);
		propertyGroups.put(group.getName(), group);
	}

	public void addPropertyCharacteristic(PropertyCharacteristic pc) {
		pc.setCategory(this);
		characteristicsMap
				.put(pc.getCharacteristic(PropertyCharacteristic.CHAR_PROPERTY_NAME_LABEL),
						pc);
	}

	public PropertyGroup getPropertyGroup(String name) {
		return propertyGroups.get(name);
	}

	public Map<String, PropertyCharacteristic> getChracteristicsMap() {
		characteristicsMap.remove(null);
		characteristicsMap.remove("");
		return characteristicsMap;
	}

	public PropertyCharacteristic getCharacteristics(String propertyName) {
		return characteristicsMap.get(propertyName);
	}

	public void setPropertyCharacteristic(String propertyName,
			PropertyCharacteristic pChar) {
		characteristicsMap.put(propertyName, pChar);
	}

	public void addParsedDocument(ParsedDocument doc) {
		doc.setCategory(this);
		documents.put(doc.getName(), doc);
		ldocuments.put(doc.getName().toLowerCase().replace(' ', '_'), doc);
		for (String s : doc.getProps().keySet())
			propertyNames.add(s);
	}

	public ParsedDocument getParsedDocument(String name) {
		ParsedDocument parsedDocument = documents.get(name);
		if (parsedDocument == null) {
			parsedDocument = ldocuments.get(name.toLowerCase()
					.replace(' ', '_'));
		}
		return parsedDocument;
	}

	public Collection<ParsedDocument> getDocumentsList() {
		return documents.values();
	}

	public Collection<String> getDocumentNamesList() {
		return documents.keySet();
	}

	public Collection<ParsedDocument> getSubcategoryDocuments(
			String categoryName) {

		HashSet<ParsedDocument> rightDocs = new HashSet<ParsedDocument>();
		ParsedDocument root = this.getParsedDocument(categoryName);
		if (root == null)
			return new ArrayList<ParsedDocument>();

		rightDocs.add(root);
		HashSet<ParsedDocument> wrongDocs = new HashSet<ParsedDocument>();
		ArrayList<ParsedDocument> buffer = new ArrayList<ParsedDocument>();

		for (ParsedDocument pd : documents.values())
			checkMembership(pd, root, rightDocs, wrongDocs, 0);

		return new ArrayList<ParsedDocument>(rightDocs);
	}

	// StringPool refsPool = new StringPool() ;
	// StringPool captionsPool = new StringPool() ;
	//
	// @Override
	// public StringPool getStringPool( String name )
	// {
	// if( name.equals(IPropertyConstants.WIKI_REFS_POOL_ID ) )
	// return refsPool ;
	//
	// if( name.equals(IPropertyConstants.WIKI_REFS_CAPTIONS_POOL_ID) )
	// return captionsPool ;
	//
	// return null ;
	// }

	private boolean checkMembership( ParsedDocument doc, ParsedDocument root , Set<ParsedDocument> right, Set<ParsedDocument> wrong,int level )
	{
		
		if( right.contains( doc ) )
			return true ;
		
		if( wrong.contains( doc ) )
			return false ;
		System.out.println(doc.getName()+":"+root.getName());
		if (level>20){
			return false;
		}
	
		//remember that roots of the parsed category have empty set of parents 
		try{		
		for( ParsedDocument parent : doc.getParentCategories() ){
			if (parent.getName().toLowerCase().replace(' ', '_').equals(doc.getName().toLowerCase().replace(' ', '_'))){
				continue;
			}
			if( checkMembership( parent, root, right, wrong,level+1) )
			{
				right.add( doc ) ;
				return true ;
			}
		}
		}catch(Exception e)
		{
			//e.printStackTrace() ;
			System.out.println(doc.getName()+":"+root.getName());
		}
		
		wrong.add( doc ) ;
		return false ;
	}

	public ArrayList<String> getPropertiesList() {
		return new ArrayList<String>(propertyNames);
	}

	public HashSet<String> getPropertyNames() {
		return propertyNames;
	}

	public void collectStats() {
		if (analyzer == null) {
			analyzer = new PropertyAnalyzer();
			analyzer.processParsedCategory(this);
		}
	}

	public HashMap<String, PropertyStats> getStats() {
		if (analyzer == null)
			collectStats();

		return analyzer != null ? analyzer.getStatsMap() : null;
	}

	public void clearDocuments() {
		this.documents.clear();
		ldocuments.clear();
	}

	public int getSize() {
		return documents.size();
	}

	public String getRootPath() {
		return rootPath;
	}

	public LinkStorage getRefs() {
		return refs;
	}

	public LinkStorage getCaptions() {
		return captions;
	}

	public void initRefs(Element element) {
		this.refs = new LinkStorage(element);
	}

	public void initCaptions(Element element) {
		this.captions = new LinkStorage(element);
	}

	public void setRefs(LinkStorage newRefs) {
		this.refs = newRefs;
	}

	public void setCaptions(LinkStorage newCaptions) {
		this.captions = newCaptions;
	}

}
